package org.oschina.plugin;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.MethodUtils;
import org.oschina.Constants;
import org.oschina.helper.ApplicationHelper;
import org.oschina.plugin.annotation.PluginAspect;
import org.oschina.plugin.bean.PluginBean;
import org.oschina.util.ReflectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class PluginHelper {

	private final static Logger logger=LoggerFactory.getLogger(PluginHelper.class);
	
	private final List<PluginBean> PLUGIN_BEANS=new ArrayList<PluginBean>();
	private final Map<PluginType,String> PLUGIN_METHODS=new HashMap<PluginType,String>();
	private boolean inited=false;
	private boolean sorted=false;
	
	private final Class PLUGIN_ABSTRACT=AbstractPlugin.class;
	
	/**
	 * 执行插件
	 * @param type
	 * @param args
	 */
	public void execute(PluginType type,Object...args)
	{
		if(!Constants.PLUGIN_ENABLED)
			return;
		
		List<PluginBean> pluginBeans=_getAll();
		String method=_getMethod(type);
		for(PluginBean plugin:pluginBeans)
		{
			if(plugin.getEnabled())
			{
				try
				{
					_showExecuteRecord(type,method,plugin);
					MethodUtils.invokeMethod(_getInstance(plugin.getTarget()), method, args);
				}
				catch(Exception e)
				{
					logger.error("'{}' - '{}' 插件执行错误 - ",plugin.getName(),plugin.getTarget().getName(),e);
				}
			}
		}
	}
	
	/**
	 * 初始化
	 */
	public void init()
	{
		if(inited)
			return;
		inited=true;
		
		Map<String, Object> classes=ApplicationHelper.getBeansOfType(PLUGIN_ABSTRACT);
		for(Object instance:classes.values())
			add(instance);

		_initAspect();
		execute(PluginType.INIT,ApplicationHelper.getServletContext());
	}
	
	/**
	 * 获得所有插件
	 * @return
	 */
	public List<PluginBean> getPlugins()
	{
		List<PluginBean> pluginBeans=new ArrayList<PluginBean>();
		for(PluginBean pluginBean:PLUGIN_BEANS)
		{
			IPlugin plugin=(IPlugin) _getInstance(pluginBean.getTarget());
			pluginBean.setName(plugin.getName());
			pluginBean.setExplain(plugin.getExplain());
			pluginBean.setClazz(plugin.getClass().getName());
			pluginBeans.add(pluginBean);
		}
		return pluginBeans;
	}
	
	/**
	 * 移除插件
	 * @param id
	 * @return
	 */
	public boolean remove(int id)
	{
		synchronized(PLUGIN_BEANS)
		{
			Iterator<PluginBean> iterator=PLUGIN_BEANS.iterator();
			while(iterator.hasNext())
			{
				PluginBean pluginBean=iterator.next();
				if(pluginBean.getId().equals(id))
				{
					ApplicationHelper.removeBean(pluginBean.getTarget());
					iterator.remove();
					return true;
				}
			}
			return false;
		}
	}
	
	/**
	 * 添加插件
	 * @param clazz
	 * @return
	 */
	public PluginBean add(Class clazz)
	{
		if(ApplicationHelper.getBean(clazz)==null)
			ApplicationHelper.createBean(clazz);
		
		return add(ApplicationHelper.getBean(clazz));
	}
	
	/**
	 * 添加插件
	 * @param instance
	 * @return
	 */
	public PluginBean add(Object instance)
	{
		Class clazz=instance.getClass();
		if(!_isPlugin(clazz))
			return null;
		
		synchronized(PLUGIN_BEANS)
		{
			IPlugin plugin=(IPlugin)instance;
			PluginBean pluginBean=new PluginBean();
			pluginBean.setId(PLUGIN_BEANS.size()+1);
			pluginBean.setTarget(clazz);
			pluginBean.setOrder(plugin.getOrder());
			PLUGIN_BEANS.add(pluginBean);
			
			sorted=false;
			return pluginBean;
		}
	}

	/**
	 * 设置激活
	 * @param id
	 * @param enabled
	 * @return
	 */
	public boolean setEnabled(int id,boolean enabled)
	{
		PluginBean pluginBean=_findById(id);
		if(pluginBean==null)
			return false;
		
		pluginBean.setEnabled(enabled);
		return true;
	}
	
	/**
	 * 获得所有
	 * @return
	 */
	private List<PluginBean> _getAll()
	{
		sort();
		return PLUGIN_BEANS;
	}
	
	/**
	 * 排序
	 */
	private void sort()
	{
		if(sorted)
			return;
		
		PluginComparator.sort(PLUGIN_BEANS);
		sorted=true;
	}
	
	/**
	 * 根据ID返回
	 * @return
	 */
	private PluginBean _findById(int id)
	{
		for(PluginBean pluginBean:PLUGIN_BEANS)
		{
			if(pluginBean.getId().equals(id))
				return pluginBean;
		}
		
		return null;
	}
	
	/**
	 * 获得所有实例
	 * @return
	 */
	private List<Object> _getInstances()
	{
		List<Object> instances=new ArrayList<Object>();
		for(PluginBean pluginBean:PLUGIN_BEANS)
		{
			Object plugin=_getInstance(pluginBean.getTarget());
			if(plugin!=null)
				instances.add(plugin);
		}
		return instances;
	}
	
	
	/**
	 * 获得实例
	 * @param clazz
	 * @return
	 */
	private Object _getInstance(Class clazz)
	{
		Object instance=ApplicationHelper.getBean(clazz);
		if(instance==null)
			logger.error("{} - 没有注册到容器",clazz);
		return instance;
	}
	
	/**
	 * 获得方法名称
	 * @param type
	 * @return
	 */
	private String _getMethod(PluginType type)
	{
		return PLUGIN_METHODS.get(type);
	}
	
	/**
	 * 初始化切面
	 */
	private void _initAspect()
	{
		Method methods[]=PLUGIN_ABSTRACT.getMethods();
		for(Method method:methods)
		{
			PluginAspect pluginAspect=(PluginAspect)ReflectUtil.getAnnotationByMethod(method, PluginAspect.class);
			if(pluginAspect!=null)
				PLUGIN_METHODS.put(pluginAspect.type(), method.getName());
		}
	}
	
	/**
	 * 是否是插件
	 * @param clazz
	 * @return
	 */
	private boolean _isPlugin(Class clazz)
	{
		return (clazz.getSuperclass().equals(PLUGIN_ABSTRACT));
	}
	
	/**
	 * 执行记录
	 * @param type
	 * @param method
	 * @param plugin
	 */
	private void _showExecuteRecord(PluginType type,String method,PluginBean plugin)
	{
		if(!Constants.PLUGIN_EXECUTE_RECORD)
			return;
		
		logger.info("执行插件 - type:'{}' - method:'{}' - class:'{}'",type,method,plugin.getTarget());
	}
}